package monitor.model.dao;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import monitor.model.parameter.EcuParameter;
import monitor.model.parameter.TimePoint;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;

/**
 * Singleton DAO class
 * 
 * Implements CRUD operations for ECU data. 
 * CRUD operations are used to insert and retrieve ECU data for selected car.
 *
 */
public class HistoryDAO {
	private DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
	
	private static HistoryDAO instance;
	
	private HistoryDAO() {
	}
	
	public static HistoryDAO getInstance() {
		if(instance == null) {
			instance = new HistoryDAO();
		}
		return instance;
	}
	
	public List<Entity> retrieveAllEntitiesInRange(String carId, Date date, Date timeFrom, Date timeTo, int page, int pageSize) {
		Key ecuGroupKey = KeyFactory.createKey("EcuParent", carId);
		
		Query query = new Query("EcuParameters", ecuGroupKey).setAncestor(ecuGroupKey);
		Calendar calendar = Calendar.getInstance();
		
		calendar.set(1900 + date.getYear(), date.getMonth(), date.getDate(), timeFrom.getHours(), timeFrom.getMinutes(), 0);
		query.addFilter(TimePoint.DATE_MILLIS, FilterOperator.GREATER_THAN_OR_EQUAL, calendar.getTimeInMillis());
		
		calendar.set(1900 + date.getYear(), date.getMonth(), date.getDate(), timeTo.getHours(), timeTo.getMinutes(), 59);
		query.addFilter(TimePoint.DATE_MILLIS, FilterOperator.LESS_THAN_OR_EQUAL, calendar.getTimeInMillis());
		
		PreparedQuery preparedQuery = this.datastoreService.prepare(query);

		List<Entity> result = preparedQuery.asList(FetchOptions.Builder.withLimit(pageSize).offset(page * pageSize));
		
		return result;
	}
	
	public void insertEcuData(String carId, List<TimePoint> timePoints) throws Exception {
		for (TimePoint point : timePoints) {
			Key ecuGroupKey = KeyFactory.createKey("EcuParent", carId);
			Entity entity = new Entity("EcuParameters", ecuGroupKey);

			entity.setProperty(TimePoint.DATE_MILLIS, point.getDateMillis());
			entity.setProperty(TimePoint.LAT, point.getLat());
			entity.setProperty(TimePoint.LNG, point.getLng());
			for (EcuParameter ecuParameter : point.getParameters()) {
				entity.setProperty(ecuParameter.getType().getNameAvg(), ecuParameter.getValueAvg());
				entity.setProperty(ecuParameter.getType().getNameMax(), ecuParameter.getValueMax());
			}
			this.datastoreService.put(entity);
		}

	}
}
